package table

import (
	"errors"
	"fmt"
	"rdSql/util"
	"reflect"
)

var (
	FiledNotExist        = errors.New("filed not exist")
	FiledValTypeNotMatch = errors.New("filed value type not match")
	FiledValTypeNotFound = errors.New("filed value type not found")
)

type RTable interface {
	TableName() string
}

// defined table struct
type TableHandler struct {
	Table     RTable
	TbName    string
	TFields   []*TField
	KeyExist  map[string]bool
	ParseVal  map[string]string
	RdxVal    map[string]int64 // index map,member is key and score is value.
	TFieldVal []string
	TFieldKey []string
	QuerySql  string // generate redis query sql
}

func NewDefaultTable(rt RTable) *TableHandler {
	return &TableHandler{Table: rt,
		ParseVal: make(map[string]string),
		RdxVal:   make(map[string]int64),
		KeyExist: make(map[string]bool),
	}
}

func (q *TableHandler) getTableName() string {
	return q.Table.TableName()
}

func (q *TableHandler) Parse() {
	q.TFields = q.traverseQ()
	q.TbName = q.getTableName()
	q.TFieldVal = []string{}
	q.TFieldKey = []string{}
	for _, tField := range q.TFields {
		q.KeyExist[tField.FieldKey] = true
		q.TFieldVal = append(q.TFieldVal, tField.FieldValStr)
		q.TFieldKey = append(q.TFieldKey, tField.FieldKey)
		q.ParseVal[tField.FieldKey] = tField.FieldValStr
	}
}

func (q *TableHandler) traverseQ() []*TField {
	elem := reflect.ValueOf(q.Table).Elem()
	typ := reflect.TypeOf(q.Table).Elem()
	eleLen := elem.NumField()
	fields := make([]*TField, eleLen)
	for i := 0; i < eleLen; i++ {
		oneField := elem.Field(i)
		oneTyp := typ.Field(i)
		tag := oneTyp.Tag
		rfVal, ok := tag.Lookup("rf")
		if !ok {
			rfVal = oneTyp.Name
		}
		_, isRds := tag.Lookup("rdx")
		oneTField := NewTFiled(rfVal, oneField.Interface(), FType(oneTyp.Type.Kind()), isRds)
		oneTField.buildFiled()
		fields[i] = oneTField
	}
	return fields
}

func (q *TableHandler) GetKeyPre(valueExtra string) string {
	return fmt.Sprintf("%s%s%s", util.TablePre, q.TbName, valueExtra)
}

// 通过where条件查询，不忽略是table字段初始化的类型
func GetSelectKey(rTable RTable, wherePars map[string]interface{}) (string, error) {
	q := NewDefaultTable(rTable)
	var searchFields = make(map[string]bool)
	elem := reflect.ValueOf(q.Table).Elem()
	for whereKey, whereVal := range wherePars {
		fieldByNameVal := elem.FieldByName(Capitalize(whereKey))
		if !fieldByNameVal.CanSet() {
			return "", FiledNotExist
		}
		switch fieldByNameVal.Kind() {
		case reflect.Int:
			if _, ok := whereVal.(int); !ok {
				return "", FiledValTypeNotMatch
			}
		case reflect.Int64:
			if _, ok := whereVal.(int64); !ok {
				return "", FiledValTypeNotMatch
			}
		case reflect.Float64:
			if _, ok := whereVal.(float64); !ok {
				return "", FiledValTypeNotMatch
			}
		case reflect.Float32:
			if _, ok := whereVal.(float32); !ok {
				return "", FiledValTypeNotMatch
			}
		case reflect.String:
			if _, ok := whereVal.(string); !ok {
				return "", FiledValTypeNotMatch
			}
		case reflect.Bool:
			if _, ok := whereVal.(bool); !ok {
				return "", FiledValTypeNotMatch
			}
		default:
			return "", FiledValTypeNotFound
		}
		searchFields[whereKey] = true
		fieldByNameVal.Set(reflect.ValueOf(whereVal))
	}
	return q.toQStr(true, searchFields), nil
}

// 通过结构图查询，忽略是table字段初始化的类型
func GetRTableSelectKey(rTable RTable) (string, error) {
	q := NewDefaultTable(rTable)
	var searchFields = make(map[string]bool)
	elem := reflect.ValueOf(q.Table).Elem()
	typ := reflect.TypeOf(q.Table).Elem()
	for i := 0; i < elem.NumField(); i++ {
		oneField := elem.Field(i)
		tag := typ.Field(i).Tag
		var searchFieldKey string
		rfVal, ok := tag.Lookup("rf")
		if !ok {
			searchFieldKey = LowCase(typ.Field(i).Name)
		} else {
			searchFieldKey = rfVal
		}
		if !oneField.IsZero() {
			searchFields[searchFieldKey] = true
		}
	}
	return q.toQStr(true, searchFields), nil
}

func (q *TableHandler) toQStr(initHandle bool, searchFields map[string]bool) string {
	var qStr string
	q.Parse()
	for _, tField := range q.TFields {
		if !searchFields[tField.FieldKey] {
			qStr += util.Symbol + util.Wildcard
			continue
		}
		if !initHandle {
			if ((tField.FieldType == Int ||
				tField.FieldType == Int64 ||
				tField.FieldType == Float64 ||
				tField.FieldType == Float32) && tField.FieldValStr == "0") ||
				(tField.FieldType == String && tField.FieldValStr == "") ||
				(tField.FieldType == Bool && tField.FieldValStr == "false") {
				qStr += util.Symbol + util.Wildcard
				continue
			}
		}
		qStr += util.Symbol + tField.FieldValStr
	}
	return q.GetKeyPre(qStr)
}

//字符首字母大写转换
func Capitalize(str string) string {
	var upperStr string
	vv := []rune(str) // 后文有介绍
	for i := 0; i < len(vv); i++ {
		if i == 0 {
			if vv[i] >= 97 && vv[i] <= 122 { // 后文有介绍
				vv[i] -= 32 // string的码表相差32位
				upperStr += string(vv[i])
			} else {
				return str
			}
		} else {
			upperStr += string(vv[i])
		}
	}
	return upperStr
}

//字符首字母大写转换
func LowCase(str string) string {
	var upperStr string
	vv := []rune(str) // 后文有介绍
	for i := 0; i < len(vv); i++ {
		if i == 0 {
			if vv[i] >= 65 && vv[i] <= 90 { // 后文有介绍
				vv[i] = +32 // string的码表相差32位
				upperStr += string(vv[i])
			} else {
				return str
			}
		} else {
			upperStr += string(vv[i])
		}
	}
	return upperStr
}
